package nc.ui.rino;

import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseAdapter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import javax.swing.DefaultListSelectionModel;
import javax.swing.JTable;
import javax.swing.ListSelectionModel;
import javax.swing.event.ListSelectionListener;
import javax.swing.event.TableModelEvent;
import javax.swing.event.TableModelListener;
import javax.swing.table.DefaultTableModel;
import javax.swing.table.TableColumn;
import javax.swing.table.TableColumnModel;
import javax.swing.table.TableModel;

import org.apache.commons.lang.ArrayUtils;

import nc.ui.pub.beans.UIMenuItem;
import nc.ui.pub.beans.UIPopupMenu;
import nc.ui.pub.bill.BillItem;
import nc.ui.pub.bill.BillModel;
import nc.ui.pub.bill.BillModelCellEditableController;
import nc.ui.pub.bill.BillSortListener2;
import nc.ui.pub.bill.IBillItem;

/**
 * @author zip
 * @date Apr 15, 2013 5:52:41 PM
 * @type nc.ui.rino.MultiSelector
 */
public class MultiSelector implements IMultiSelector, TableModelListener, BillModelCellEditableController, BillSortListener2 {
	private BillItem billItemMultiSelector;

	private JTable table; // the table

	private UIPopupMenu pmHead;

	private ActionListener pmListener = null;

	private TableColumn selectionColumn; // select col

	private ListSelectionModel selectionModel = new DefaultListSelectionModel();

	private class HeaderPopupMenuActionListener implements ActionListener {
		public void actionPerformed(ActionEvent e) {
			if (e.getActionCommand().equals(SEL_ALL)) {
				selectAllRow();
			} else if (e.getActionCommand().equals(SEL_NOT_ALL)) {
				selectNone();
			} else if (e.getActionCommand().equals(SEL_RESVERSE)) {
				reverseSelect();
			}
		}
	}

	private class HeaderPopupMouseAdapter extends MouseAdapter {
		public void mouseReleased(java.awt.event.MouseEvent e) {
			TableColumnModel colModel = table.getTableHeader().getColumnModel();
			int index = colModel.getColumnIndexAtX(e.getX());
			if (getSelColName().equals(colModel.getColumn(index).getHeaderValue())) {
				getPmHead().show((Component) e.getSource(), e.getX(), e.getY());
			}
		}
	}

	public MultiSelector() {
		this(null);
	}

	public MultiSelector(JTable newTable) {
		super();
		this.table = newTable;
		init();
	}

	public void addListSelectionListener(ListSelectionListener x) {
		selectionModel.addListSelectionListener(x);
	}

	public void addMultiSeletor(JTable newTable) {
		if (newTable == null) { return; }
		table = newTable;
		init();
	}

	private void addSelectionColumn() {
		if (table == null) { return; }
		DefaultTableModel model = (DefaultTableModel) table.getModel();
		BillItem[] billItems = null;
		if (model instanceof BillModel) {
			BillModel billModel = (BillModel) model;
			billItems = billModel.getBodyItems();
			if (billItemMultiSelector == null) {
				billItemMultiSelector = new BillItem();
				billItemMultiSelector.setName(getSelColName());
				billItemMultiSelector.setKey(SEL_COL_CODE);
				billItemMultiSelector.setDataType(IBillItem.BOOLEAN);
				billItemMultiSelector.setNull(false);
				billItems = (BillItem[]) ArrayUtils.add(billItems, billItemMultiSelector);
				billModel.setBodyItems(billItems);
				TableColumn tableColumn = new TableColumn();
				tableColumn.setIdentifier(getSelColName());
				table.getColumnModel().addColumn(tableColumn);
			}
			billModel.setCellEditableController(this);
			table.setModel(billModel);
		}

		selectionColumn = table.getColumn(getSelColName());
		if (selectionColumn == null) return;
		selectionColumn.setWidth(40);
		selectionColumn.setMaxWidth(40);
		selectionColumn.setResizable(false);
		table.getTableHeader().addMouseListener(new HeaderPopupMouseAdapter());
	}

	public void addSelectionInterval(int from, int to) {
		setSelectionState(from, to, true);
	}

	public void currentRowChange(int row) {
		TableModel tableModel = getTable().getModel();
		tableChanged(new TableModelEvent(tableModel, 0, tableModel.getRowCount() - 1, tableModel.getColumnCount() - 1, TableModelEvent.UPDATE));
	}

	public int getMaxSelectionIndex() {
		if (table.getRowCount() == 0) { return -1; }

		return selectionModel.getMaxSelectionIndex();
	}

	public int getMinSelectionIndex() {
		if (table.getRowCount() == 0) { return -1; }

		return selectionModel.getMinSelectionIndex();
	}

	/*********************************************************************************************************
	 * @return Returns the pmHead.
	 ********************************************************************************************************/
	public UIPopupMenu getPmHead() {
		if (pmHead == null) {
			pmHead = new UIPopupMenu();

			UIMenuItem miSelAll = new UIMenuItem(SEL_ALL_NAME);
			miSelAll.setActionCommand(SEL_ALL);
			miSelAll.addActionListener(getPmListener());

			UIMenuItem miNotSelAll = new UIMenuItem(SEL_NOT_ALL_NAME);
			miNotSelAll.setActionCommand(SEL_NOT_ALL);
			miNotSelAll.addActionListener(getPmListener());

			UIMenuItem miReverseSel = new UIMenuItem(SEL_RESVERSE_NAME);
			miReverseSel.setActionCommand(SEL_RESVERSE);
			miReverseSel.addActionListener(getPmListener());

			pmHead.add(miSelAll);
			pmHead.add(miNotSelAll);
			pmHead.add(miReverseSel);
		}

		return pmHead;
	}

	public ActionListener getPmListener() {
		if (pmListener == null) {
			pmListener = new HeaderPopupMenuActionListener();
		}
		return pmListener;
	}

	public String getSelColName() {
		return SEL_COL_NAME;
	}

	public int getSelectedRow() {
		return getMinSelectionIndex();
	}

	public int[] getSelectedRows() {
		int iMin = getMinSelectionIndex();
		int iMax = getMaxSelectionIndex();

		if (iMin == -1 || iMax == -1) { return new int[0]; }

		int n = 0;
		int[] rvTmp = new int[1 + iMax - iMin];

		for (int i = iMin; i <= iMax; i++) {
			if (selectionModel.isSelectedIndex(i)) {
				rvTmp[n++] = i;
			}
		}

		int[] rv = new int[n];

		System.arraycopy(rvTmp, 0, rv, 0, n);

		return rv;
	}

	public JTable getTable() {
		return table;
	}

	private void init() {
		if (table == null) { return; }
		DefaultTableModel model = (DefaultTableModel) table.getModel();
		if (model instanceof BillModel) {
			BillModel billModel = (BillModel) model;
			billModel.addBillSortListener2(this);

			BillItem[] billItems = billModel.getBodyItems();

			for (BillItem billItem : billItems) {
				if (SEL_COL_CODE.equals(billItem.getKey())) {
					billItemMultiSelector = billItem;
					break;
				}
			}
		}

		// add the sel column and listen the edit event
		addSelectionColumn();
		getTable().getModel().addTableModelListener(this);
	}

	public boolean isCellEditable(boolean value, int row, String itemkey) {
		// if the sel col ,will can edit whatever.
		if (itemkey.equals(SEL_COL_CODE)) { return true; }

		return value;
	}

	public boolean isSelected(int index) {
		return selectionModel.isSelectedIndex(index);
	}

	public boolean isSelectionEmpty() {
		return selectionModel.isSelectionEmpty();
	}

	public void removeListSelectionListener(ListSelectionListener x) {
		selectionModel.removeListSelectionListener(x);
	}

	public void removeMultiSelector() {
		if (table != null && selectionColumn != null) {
			table.getColumnModel().removeColumn(selectionColumn);

			removeSelectionColumn();

			table.updateUI();
		}
	}

	private void removeSelectionColumn() {
		if (table == null) { return; }

		DefaultTableModel model = (DefaultTableModel) table.getModel();

		if (model instanceof BillModel) {
			BillModel billModel = (BillModel) model;

			BillItem[] billItems = billModel.getBodyItems();

			List<BillItem> list = new ArrayList<BillItem>();
			list.addAll(Arrays.asList(billItems));

			for (BillItem billItem : billItems) {
				if (SEL_COL_CODE.equals(billItem.getKey())) {
					list.remove(billItem);
					break;
				}
			}
			billModel.setBodyItems(list.toArray(new BillItem[list.size()]));
			// billModel.setCellEditableController(this);
		}
	}

	public void removeSelectionInterval(int from, int to) {
		setSelectionState(from, to, false);
	}

	public void reverseSelect() {
		for (int i = 0; i < getTable().getRowCount(); i++) {
			if (selectionModel.isSelectedIndex(i)) {
				getTable().getModel().setValueAt(new Boolean(false), i, selectionColumn.getModelIndex());
			} else {

				if (getTable().getModel().isCellEditable(i, selectionColumn.getModelIndex())) {
					Boolean isSelected = (Boolean) getTable().getModel().getValueAt(i, selectionColumn.getModelIndex());
					if (isSelected != null && isSelected.booleanValue()) {
						getTable().getModel().setValueAt(new Boolean(false), i, selectionColumn.getModelIndex());
					} else {
						getTable().getModel().setValueAt(new Boolean(true), i, selectionColumn.getModelIndex());
					}
				}
			}
		}
	}

	public void selectAllRow() {
		addSelectionInterval(0, getTable().getRowCount() - 1);
	}

	public void selectNone() {
		removeSelectionInterval(0, getTable().getRowCount() - 1);
		selectionModel.clearSelection();
	}

	public void setPmHead(UIPopupMenu pmHead1) {
		this.pmHead = pmHead1;
	}

	public void setPmListener(ActionListener pmListener1) {
		this.pmListener = pmListener1;
	}

	public void setSelColumn(TableColumn selColumn1) {
		this.selectionColumn = selColumn1;
	}

	public void setSelectionInterval(int from, int to) {
		selectNone();
		addSelectionInterval(from, to);
	}

	private void setSelectionState(int iFromIndex, int iToIndex, boolean blIsSelected) {
		for (int i = iFromIndex; i <= iToIndex; i++) {
			if (getTable().getModel().isCellEditable(i, selectionColumn.getModelIndex())) {
				getTable().getModel().setValueAt(new Boolean(blIsSelected), i, selectionColumn.getModelIndex());
			}
		}
	}

	public void tableChanged(TableModelEvent e) {
		if (e.getColumn() < TableModelEvent.ALL_COLUMNS) { return; }

		if (e.getType() == TableModelEvent.INSERT && e.getColumn() == TableModelEvent.ALL_COLUMNS) {
			if (e.getFirstRow() == e.getLastRow() && e.getFirstRow() >= 0) {
				selectionModel.clearSelection();
				selectionModel.removeSelectionInterval(e.getFirstRow(), e.getFirstRow());
			}
		} else if (e.getType() == TableModelEvent.UPDATE && e.getColumn() > TableModelEvent.ALL_COLUMNS && getTable().getModel().getColumnName(e.getColumn()).equals(getSelColName())) {
			for (int i = e.getFirstRow(); i <= e.getLastRow(); i++) {
				Boolean val = (Boolean) getTable().getModel().getValueAt(i, e.getColumn());

				if (val == null || val.booleanValue() == false) {
					selectionModel.removeSelectionInterval(i, i);
				} else {
					selectionModel.addSelectionInterval(i, i);
				}
			}
		}

		else if (e.getType() == TableModelEvent.DELETE && e.getColumn() == TableModelEvent.ALL_COLUMNS) {
			selectionModel.removeIndexInterval(e.getFirstRow(), e.getLastRow());
		}
	}
}